//****************************************************
// Porman Project 
// Filename: CRenderSystem.cpp
// Date: 2010/12/13
// Author: KengYu Lin
// Modify:
//****************************************************
#include "CRenderSystem.h"

namespace Porman
{

namespace RS
{

CRenderSystem* CRenderSystem::getSingletonPtr(void)
{
    return ms_Singleton;
}
CRenderSystem& CRenderSystem::getSingleton(void)
{  
    assert( ms_Singleton );  return (*ms_Singleton);  
}

CRenderSystem::CRenderSystem( CRenderSystemDesc& desc, IRenderMutex* pMutex ) :
m_RenderSysDesc(desc),
m_pDevice(NULL),
//m_vectTempUnities(),
m_mapRenderUnities(),
m_mapRenderCameras(),
m_mapRenderWindows()
{
    if( !pMutex )
    {
        m_pMutex = new CDefaultRenderMutex();
        m_bUsingDefaultRenderMutex = true;
    }
    else
    {
        m_pMutex = pMutex;
        m_bUsingDefaultRenderMutex = false;
    }
}

CRenderSystem::~CRenderSystem( void )
{
    if( m_bUsingDefaultRenderMutex )
    {
        SAFEDELETE( m_pMutex );
    }

    if( m_pDevice )
        GL::CDeviceCreator::destroyDevice( &m_pDevice );
}

bool CRenderSystem::initialise( CRenderWindow* pWindow )
{
    if( pWindow )
    {
        if( !m_pDevice )
        {
            if( GL::CDeviceCreator::createDevice( pWindow->getRenderCanvas(), &m_pDevice ) == GL::E_SUCCESS )
                return true;
        }
        else
            return true;
    }

    assert(0);
    return false;
}

bool CRenderSystem::isInitialised( void )
{
    return (m_pDevice ? true: false);
}

CRenderWindow* CRenderSystem::createRenderWindow( HWND hWnd, const std::string& sName )
{
    CRenderWindow* pWindow = m_mapRenderWindows.createObj( sName );
    if( pWindow )
    {
        GL::CRenderCanvas* pCanvas = pWindow->getRenderCanvas();
        if( !pCanvas )
        {
            if( GL::CDeviceCreator::createCanvas( hWnd, &m_RenderSysDesc, &pCanvas ) == GL::E_SUCCESS )
                pWindow->initial( pCanvas );
            else
            {
                assert(0);
                deleteRenderWindow( &pWindow );
            }
        }
        else
        {
            if( pCanvas->m_hWnd == hWnd )
                pWindow->initial( pCanvas );
            else
            {
                assert(0);
                deleteRenderWindow( &pWindow );
            }
        }
    }
    return pWindow;
}

bool CRenderSystem::deleteRenderWindow( CRenderWindow** ppWindow )
{
    MUTEXLOCK();
    GL::CRenderCanvas* pCanvas = (*ppWindow)->getRenderCanvas();
    if( pCanvas )
        GL::CDeviceCreator::destroyCanvas( &(pCanvas) );

    return m_mapRenderWindows.deleteObj( ppWindow, true );
}

CRenderWindow* CRenderSystem::getRenderWindow( const std::string& sName )
{
    return m_mapRenderWindows.getObj( sName );
}

int CRenderSystem::getNumRenderWindows( void )
{
    return m_mapRenderWindows.getNumObj();
}

CRenderCamera* CRenderSystem::createRenderCamera( const std::string& sName )
{
    CRenderCamera* pCamera = m_mapRenderCameras.createObj( sName );
    if( pCamera )
        pCamera->initial();

    return pCamera;
}

bool CRenderSystem::deleteRenderCamera( CRenderCamera** ppCamera )
{
    return m_mapRenderCameras.deleteObj( ppCamera );
}

CRenderCamera* CRenderSystem::getRenderCamera( const std::string& sName )
{
    return m_mapRenderCameras.getObj( sName );
}

int CRenderSystem::getNumRenderCamera( void )
{
    return m_mapRenderCameras.getNumObj();
}

CRenderUnity* CRenderSystem::createRednerUnity( const std::string& sName )
{
    CRenderUnity* pUnity = m_mapRenderUnities.createObj( sName );
    if( pUnity )
        pUnity->initial();

    return pUnity;
}

bool CRenderSystem::deleteRednerUnity( CRenderUnity** ppUnity )
{
    return m_mapRenderUnities.deleteObj( ppUnity );
}

CRenderUnity* CRenderSystem::getRednerUnity( const std::string& sName )
{
    return m_mapRenderUnities.getObj( sName );
}

int CRenderSystem::getNumRenderUnity( void )
{
    return m_mapRenderUnities.getNumObj();
}

void CRenderSystem::onSwap( void )
{
    if( !isInitialised() ) 
    {
        assert(0);
        return;
    }

    //--------------------------------------
    // Merge and Swap RenderUnity:
    //--------------------------------------   
    m_mapRenderUnities.onMerge();
    m_mapRenderUnities.onSwap();
    m_mapRenderUnities.onClear();

    //--------------------------------------
    // Merge and Swap RenderCamera:
    //--------------------------------------
    m_mapRenderCameras.onMerge();
    m_mapRenderCameras.onSwap();
    m_mapRenderCameras.onClear();

    //--------------------------------------
    // Merge and Swap RenderWindows:
    //--------------------------------------
    m_mapRenderWindows.onMerge();
    m_mapRenderWindows.onSwap();

    return;
}

void CRenderSystem::onRender( void )
{
    if( !isInitialised() ) 
    {
        assert(0);
        return;
    }

    if( m_pDevice->beginThread() )
    {        
        //--------------------------
        // onRender:
        //--------------------------
        CRenderWindow* pWindow = m_mapRenderWindows.getFirst();
        while( pWindow )
        {
            pWindow->onRender();
            pWindow = m_mapRenderWindows.getNext( pWindow );
        }

        pWindow = m_mapRenderWindows.getFirst();
        while( pWindow )
        {
            pWindow->swapBuffer();
            pWindow = m_mapRenderWindows.getNext( pWindow );
        }
        m_pDevice->endThread();
        return;
    }

    assert(0);
    return;
}

}//End namespace RS

}//End namespace Porman